/*
	       File: FileProcessor.cs
	Create Date: 2007-08-12
	    Version:

	Description:


	 Change log:


*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Workflow;
using System.Workflow.Activities;
using System.Workflow.Runtime;

using GuerillaProgrammer.Components.Logging;
using GuerillaProgrammer.FileProcessor.Settings;

namespace GuerillaProgrammer.FileProcessor
{
    public class FileProcessor:  IProcessorDataService
    {
        #region Private member fields
        AutoResetEvent _WaitHandle; //this will have to change
        private Configuration _Configuration;
        private WorkItem _WorkItem;
        #endregion

        #region Constructors and cleanup methods
        public FileProcessor(WorkItem workItem, Configuration configuration)
        {
            _WorkItem = workItem;
            _Configuration = configuration;
        }
        #endregion

        #region Private implementation methods
        private ConfigurationDirectory GetDirectory(string directoryID)
        {
            foreach (ConfigurationDirectory directory in _Configuration.Directories)
            {
                if (directoryID == directory.ID)
                {
                    return directory;
                }
            }

            return null;
        }
        private ConfigurationFileType GetFileType(string fileTypeID)
        {
            foreach (ConfigurationFileType fileType in _Configuration.FileTypes)
            {
                if (fileTypeID == fileType.ID)
                {
                    return fileType;
                }
            }
            return null;
        }
        private ConfigurationWorkflow GetWorkflow(string workFlowID)
        {
            foreach (ConfigurationWorkflow workflow in _Configuration.Workflows)
            {
                if (workFlowID == workflow.ID)
                {
                    return workflow;
                }
            }

            return null;
        }
        private string WorkflowTypeName()
        {
            ConfigurationFileType fileType = GetFileType(_WorkItem.FileTypeID);
            ConfigurationWorkflow workflow = GetWorkflow(fileType.WorkflowID);

            return workflow.WorkflowStrongName;
        }
        private WorkflowInstance LoadWorkflowFromAssembly(string typeName, WorkflowRuntime runTime)
        {
            try
            {
                string[] namePieces = typeName.Split(new char[] { ',' });

                string assemblyPath = string.Format("{0}.dll", Path.Combine(_Configuration.Services.AssemblyDirectory, namePieces[1].Trim()));
                Assembly wfAsm = Assembly.LoadFile(assemblyPath);

                WorkflowInstance instance = runTime.CreateWorkflow(wfAsm.GetType(namePieces[0].Trim()));

                return instance;
            }
            catch (Exception exc)
            {
                Logger.LogError("LoadAssembly Error", "An error occurred loading: {0}.\n error:\n{1}", typeName, exc.Message);
                throw exc;
            }
        }
        private WorkflowRuntime SetupRuntime()
        {
            _WaitHandle = new AutoResetEvent(false);
            WorkflowRuntime workflowRunTime = new WorkflowRuntime();
            workflowRunTime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(this.WorkflowCompleted);
            workflowRunTime.WorkflowTerminated += new EventHandler<WorkflowTerminatedEventArgs>(this.WorkflowTerminated);

            ExternalDataExchangeService dataExchangeService = new ExternalDataExchangeService();
            workflowRunTime.AddService(dataExchangeService);
            dataExchangeService.AddService((IProcessorDataService)this);

            return workflowRunTime;
        }        
        #endregion

        #region Events handlers
        private void WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
        {
            _WaitHandle.Set();
        }
        private void WorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
        {
            Logger.LogError("Workflow terminated!", "An error in the workflow: {0}\n", e.Exception.Message);
            _WaitHandle.Set();
        }
        #endregion

        #region Public interface
        public void ProcessWorkItem(object stateInfo)
        {
            try
            {
                WorkflowRuntime workflowRunTime = SetupRuntime();
                string workflowTypeName = WorkflowTypeName();

                WorkflowInstance instance = LoadWorkflowFromAssembly(workflowTypeName, workflowRunTime);

                instance.Start();
                _WaitHandle.WaitOne();

                //delete the workitem now
                File.Delete(_WorkItem.Filename);
            }
            catch (Exception exc)
            {
                Logger.LogInfo("Procss WorkItem", "An error occured while processing work item\nError: {0}\n", exc.Message);
            }
        }
        #region IProcessorDataService Members
        public Configuration GetConfiguration()
        {
            return _Configuration;
        }
        public WorkItem GetWorkItem()
        {
            return _WorkItem;
        }
        #endregion
        #endregion
    }
}
